// 运行：node mine-testnet.ts
import { createHash } from 'crypto';

const RPC_URL = process.env.BITCOIN_RPC_URL || 'http://127.0.0.1:18332';
const RPC_USER = process.env.RPC_USER || 'dev';
const RPC_PASS = process.env.RPC_PASS || 'devpass';

async function rpc(method: string, params: any[] = []) {
  const res = await fetch(RPC_URL, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Basic ' + Buffer.from(`${RPC_USER}:${RPC_PASS}`).toString('base64'),
    },
    body: JSON.stringify({ jsonrpc: '1.0', id: 'pow', method, params }),
  });
  const j = await res.json();
  if (j.error) throw new Error(JSON.stringify(j.error));
  return j.result;
}

const sha256 = (buf: Buffer) => createHash('sha256').update(buf).digest();
const dsha256 = (buf: Buffer) => sha256(sha256(buf));
const bytesToHex = (b: Buffer) => b.toString('hex');
const reverse = (b: Buffer) => Buffer.from(b).reverse();
const u32LE = (n: number) => { const b = Buffer.alloc(4); b.writeUInt32LE(n >>> 0); return b; };

// bits（compact target）转大整数目标
function bitsToTarget(bitsHex: string): bigint {
  const bits = parseInt(bitsHex, 16);
  const exp = (bits >>> 24) & 0xff;
  const mant = bits & 0x007fffff;
  return BigInt(mant) * (1n << (8n * (BigInt(exp) - 3n)));
}

// 序列化区块头（80 字节）
function serializeHeader(version: number, prevHashHex: string, merkleHex: string, time: number, bitsHex: string, nonce: number): Buffer {
  const prevLE = reverse(Buffer.from(prevHashHex, 'hex'));
  const merkleLE = reverse(Buffer.from(merkleHex, 'hex'));
  const bitsLE = reverse(Buffer.from(bitsHex, 'hex')); // 4字节LE
  return Buffer.concat([u32LE(version), prevLE, merkleLE, u32LE(time), bitsLE, u32LE(nonce)]);
}

(async () => {
  const tpl = await rpc('getblocktemplate', [{ rules: ['segwit'] }]);
  const version = tpl.version;                  // 建议版本
  const prevHash = tpl.previousblockhash;       // 上一块哈希（展示为BE）
  const time = tpl.curtime;                     // 建议时间戳
  const bits = tpl.bits;                        // 难度（compact）
  const target = bitsToTarget(bits);

  // 演示用：占位 coinbase -> merkleRoot（真实出块需要构造合法 coinbase + 交易 Merkle）
  // 提示：完整实现需用 tpl.height / tpl.coinbasevalue / tpl.default_witness_commitment 等信息
  const fakeCoinbase = Buffer.from('00', 'hex');
  const merkleRoot = bytesToHex(dsha256(fakeCoinbase)); // 仅演示

  console.log('prevHash:', prevHash);
  console.log('bits:', bits, 'target:', '0x' + target.toString(16));

  let nonce = 0;
  let best = BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff');

  for (; nonce <= 0xffffffff; nonce++) {
    const header = serializeHeader(version, prevHash, merkleRoot, time, bits, nonce);
    const hash = dsha256(header);                      // header 的双 SHA256
    const num = BigInt('0x' + bytesToHex(reverse(hash))); // 作为BE整数比较
    if (num < best) best = num;
    if ((nonce & 0xFFFFF) === 0) {
      console.log(`nonce=${nonce} best=${best.toString(16).slice(0, 16)} hash=${bytesToHex(reverse(hash))}`);
    }
    if (num <= target) {
      console.log('找到满足目标的头（演示）：', {
        nonce,
        headerHex: bytesToHex(header),
        powHash: bytesToHex(reverse(hash)),
      });
      break;
    }
  }
})().catch((e) => {
  console.error('错误:', e);
  process.exit(1);
});